以下出現之畫面皆為參照 FieC 公司開發的 Ahorro 所仿造出來的,該創意全為該公司所有,且本文之全部內容都與其公司無任何直接關係。
Ahorro - 輕鬆記帳,簡單理財
在設計 app 的時候,常會有跳出對話框的時候,而此時,通常也不會去使用內建的對話框,會依照該 app 的需求,去使用自定義的 dialog。比起內建的,自定義可以更方便的去新增更多元件,更改顏色、字型、背景等等,能依照我們的需求像之前一樣把 layout 寫好再套用。
像這個
在判斷出資料未填完就要離開時:按下確定會離開;按下取消會留下。
完成一個簡單的 yes or no dialog
這個 dialog 我只做兩個 button 跟一個 text view 顯示內容
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:background="@color/AhorroBackground_YellowLight"
android:layout_gravity="center">
<TextView
android:id="@+id/dialog_yes_no_message"
android:text="訊息"
android:textColor="@color/AhorroTextColor"
android:layout_margin="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/dialog_negative"
android:text="否"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginBottom="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:background="@drawable/ahorro_button_dialog"
android:textColor="@color/AhorroWhite"/>
<Button
android:id="@+id/dialog_positive"
android:text="是"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginBottom="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:background="@drawable/ahorro_button_dialog"
android:textColor="@color/AhorroWhite"/>
</LinearLayout>
</LinearLayout>
其中的按鈕的 background 是之前先做好的 drawable
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/AhorroDialog_GrayDark"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/AhorroDialog_Gray"/>
</shape>
</item>
</selector>
在按下時,顏色會變深
新增一個 class 繼承於 Dialog(),並用建構元把 context 丟給 dialog
override onCreate()方法,記得還要用 setContentView 把我們剛剛寫的 layout 畫面給他
class YesNoDialog(context: Context): Dialog(context){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dialog_yes_no)
}
}
在剛剛的圖片中,需要有一個 String 裝內容,跟兩個 button 的點擊監聽器接口
所以寫出各個的 setter。
之所以我們前面的 dialog 可以在 builder 後面一直小數點就可以繼續增加屬性,是因為他有回傳的關係,來看看原本 builder 的其中一個 function,
/**
* Set the title displayed in the {@link Dialog}.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(@Nullable CharSequence title) {
P.mTitle = title;
return this;
}
他的確是把整個 builder 在回傳回去的,那們我們也就仿造它的寫法
完成以後會像這樣
class YesNoDialog(context: Context): Dialog(context){
private var message: String?= null
private var cancelListener: IOnCancelListener? = null
private var confirmListener: IOnConfirmListener? = null
fun setMessage(message: String?): YesNoDialog {
this.message = message
return this
}
fun setConfirm(Listener: IOnConfirmListener): YesNoDialog {
this.confirmListener = Listener
return this
}
fun setCancel(Listener: IOnCancelListener): YesNoDialog {
this.cancelListener = Listener
return this
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dialog_yes_no)
val btNegative: Button= findViewById(R.id.dialog_negative)
val btPositive: Button= findViewById(R.id.dialog_positive)
val tvContent: TextView= findViewById(R.id.dialog_yes_no_message)
message?.let {
tvContent.text= it
}
btPositive.setOnClickListener(this::clickListener)
btNegative.setOnClickListener(this::clickListener)
}
private fun clickListener(v: View){
when(v.id){
R.id.dialog_positive -> {
confirmListener?.let {
it.onConfirm(this)
}
}
R.id.dialog_negative -> {
cancelListener?.let {
it.onCancel(this)
}
}
}
}
interface IOnCancelListener {
fun onCancel(dialog: YesNoDialog?)
}
interface IOnConfirmListener {
fun onConfirm(dialog: YesNoDialog?)
}
}
在使用上,因為一個 activity 或 fragment 可能會多次使用,我就把它分出一個 class。
private fun showDialog(message: String){
val yesNoDialog= YesNoDialog(this)
yesNoDialog
.setMessage(message)
.setCancel(object : YesNoDialog.IOnCancelListener {
override fun onCancel(dialog: YesNoDialog?) {
yesNoDialog.dismiss()
}
})
.setConfirm(object : YesNoDialog.IOnConfirmListener {
override fun onConfirm(dialog: YesNoDialog?) {
finish()
}
}).show()
}
其實用起來跟一般的 dialog 差不多,但畫面的靈活度就高上許多,往後應該也會經常用到類似的功能。